import {
  wrapFn
} from './common/wrap-fn'
import messages from './lang/index'

import * as methodList from './uni-id'

function parseContext (context) {
  return {
    appId: context.APPID,
    platform: context.PLATFORM,
    locale: context.LOCALE,
    clientIP: context.CLIENTIP,
    deviceId: context.DEVICEID
  }
}

const uniIDConfig = require('uni-config-center')({
  pluginId: 'uni-id'
})

class UniID {
  constructor ({
    context,
    clientInfo,
    config
  } = {}) {
    this._clientInfo = context ? parseContext(context) : clientInfo
    this._config = config
    this.config = this._getOriginConfig()
    this.interceptorMap = new Map()
    if (uniIDConfig.hasFile('custom-token.js')) {
      this.setInterceptor('customToken', require(uniIDConfig.resolve('custom-token.js')))
    }
    const fallbackLocale = 'zh-Hans'
    this._i18n = uniCloud.initI18n({
      locale: this._clientInfo.locale,
      fallbackLocale,
      messages: JSON.parse(JSON.stringify(messages))
    })
    if (!messages[this._i18n.locale]) {
      this._i18n.setLocale(fallbackLocale)
    }
  }

  setInterceptor (timing, handler) {
    this.interceptorMap.set(timing, handler)
  }

  _t (...args) {
    return this._i18n.t(...args)
  }

  _parseOriginConfig (configContent) {
    // require [1,2] => {0:1,1:2}
    if (Array.isArray(configContent)) {
      return configContent
    }
    return configContent[0] ? Object.values(configContent) : configContent
  }

  _getOriginConfig () {
    if (this._config) {
      return this._config
    }
    if (uniIDConfig.hasFile('config.json')) {
      let configContent
      try {
        configContent = uniIDConfig.config()
      } catch (error) {
        throw new Error('Invalid uni-id config file\n' + error.message)
      }
      return this._parseOriginConfig(configContent)
    } else {
      try {
        return this._parseOriginConfig(
          require('uni-id/config.json') // 兼容uni-id下配置文件
        )
      } catch (error) {
        throw new Error('Invalid uni-id config file')
      }
    }
  }

  _getAppConfig () {
    const originConfig = this._getOriginConfig()
    if (!Array.isArray(originConfig)) {
      return originConfig
    }
    return originConfig.find(item => item.dcloudAppid === this._clientInfo.appId) || originConfig.find(item => item.isDefaultConfig)
  }

  _getPlatformConfig () {
    const appConfig = this._getAppConfig()
    if (!appConfig) {
      throw new Error(`Config for current app (${this._clientInfo.appId}) was not found, please check your config file or client appId`)
    }
    if (['app-plus', 'app-android', 'app-ios'].indexOf(this._clientInfo.platform) > -1) {
      this._clientInfo.platform = 'app'
    }
    if (this._clientInfo.platform === 'h5') {
      this._clientInfo.platform = 'web'
    }
    let fallbackPlatform
    switch (this._clientInfo.platform) {
      case 'web':
        fallbackPlatform = 'h5'
        break
      case 'app':
        fallbackPlatform = 'app-plus'
        break
      default:
        break
    }
    const defaultConfig = {
      tokenExpiresIn: 7200,
      tokenExpiresThreshold: 1200,
      passwordErrorLimit: 6,
      passwordErrorRetryTime: 3600
    }
    const argsRequired = ['tokenSecret', 'tokenExpiresIn']
    const configList = [defaultConfig, appConfig]
    if (fallbackPlatform && appConfig[fallbackPlatform]) {
      configList.push(appConfig[fallbackPlatform])
    }
    configList.push(appConfig[this._clientInfo.platform])
    const config = Object.assign(...configList)
    argsRequired.forEach((item) => {
      if (!config || !config[item]) {
        throw new Error(`Config parameter missing, ${item} is required`)
      }
    })
    return config
  }

  _getConfig () {
    return this._getPlatformConfig()
  }
}

for (const key in methodList) {
  UniID.prototype[key] = methodList[key]
}

function createInstance (params) {
  // {
  //   context,
  //   clientInfo,
  //   config
  // } = params
  const uniIDOrigin = new UniID(params)
  const uniID = new Proxy(uniIDOrigin, {
    get (target, prop) {
      if (prop in target && prop.indexOf('_') !== 0) {
        if (typeof target[prop] === 'function') {
          return wrapFn(target[prop]).bind(target)
        } else if (prop === 'context' || prop === 'config') {

        } else {
          return target[prop]
        }
      }
    }
  })
  return uniID
}

UniID.prototype.createInstance = createInstance

const uniID = {
  // 自4.0.0版起只能使用createInstance创建实例，直接require('uni-id')仅会得到一个包含createInstance方法的对象
  createInstance
}

export default uniID
